#!/user/bin/env python3
# -*- coding: utf-8 -*-
"""
--------------------------------------
    Author:     JiChao_Song
    Date  :     2022/1/13 9:12
    Desc  :
--------------------------------------
"""
from django.conf.urls import url
from django.core.paginator import Paginator
from django.db import transaction
from django.urls import path
from django.utils.decorators import method_decorator
from django_http_log.common.request import BaseAPIView
from django_http_log.common.response import SystemExceptionResponse, SuccessResponse, CommonResponse

from common.decorator.token_decorator import Authentication
from common.enums.config_enums import DatabaseTypeEnums
from common.enums.response_enums import CommonResultEnums
from common.exceptions import DatabaseConfigConnectException, DatabaseConfigTypeException
from common.utils.log_utils import logger
from common.utils.other_utils import get_enum_str_list, get_time, get_enum_key_list
from common.utils.sql_utils import CommonSqlConfig, CommonBaseMapper, MssqlMapper, MysqlMapper
from common.utils.token_utils import RequestAuthTokenUtil
from person.models import DatabaseConfig
from person.serializers.config import DatabaseConfigSerializers
from platform_auth.settings import APIDOC_DECORATOR


class DatabaseConfigBaseAPIView(BaseAPIView):
    Model = DatabaseConfig

    serializer_class = DatabaseConfigSerializers

    def database_connect(self, serverId: int):
        """
        数据库连接
        :param serverId: 数据库id
        :return:
        """
        queryset = self.Model.objects.filter(id = serverId, deleted = False)

        if queryset.count() == 0:
            return CommonResponse(codeEnums = CommonResultEnums.DB_ID_IS_NOT_EXIST)

        database_config = queryset.first()

        connect_config = CommonSqlConfig(
            configType = database_config.dbType,
            password = database_config.password,
            user = database_config.userName,
            database = database_config.database,
            port = database_config.port,
            host = database_config.host
        )
        if connect_config.configType == 101:
            connect_config.createMysqlPool()
            if not connect_config.connected:
                raise DatabaseConfigConnectException("数据库连接异常")
            else:
                return MysqlMapper(pool = connect_config.pool)
        elif connect_config.configType == 102:
            connect_config.createMssqlPool()
            if not connect_config.connected:
                raise DatabaseConfigConnectException("数据库连接异常")
            else:
                return MssqlMapper(pool = connect_config.pool)
        else:
            raise DatabaseConfigTypeException("数据库连接不支持")


class DatabaseConfigAddAPIView(DatabaseConfigBaseAPIView):

    @APIDOC_DECORATOR.checkParams
    @APIDOC_DECORATOR.start
    @APIDOC_DECORATOR.ApiTag(value = 'config', desc = '配置管理')
    @APIDOC_DECORATOR.ApiOperation(method = 'POST', path = '/config/database/add', summary = '数据库配置新增')
    @APIDOC_DECORATOR.ApiParams(value = 'remark', type = 'string', desc = '备注')
    @APIDOC_DECORATOR.ApiParams(value = 'port', type = 'int', require = True, desc = '端口')
    @APIDOC_DECORATOR.ApiParams(value = 'host', type = 'string', require = True, desc = '数据库地址')
    @APIDOC_DECORATOR.ApiParams(value = 'password', type = 'string', require = True, desc = '密码')
    @APIDOC_DECORATOR.ApiParams(value = 'userName', type = 'string', require = True, desc = '用户名')
    @APIDOC_DECORATOR.ApiParams(value = 'database', type = 'string', require = True, desc = '数据库名')
    @APIDOC_DECORATOR.ApiParams(value = 'dbType', require = True, type = 'int', desc = '数据库类型',
                                remark = get_enum_str_list(enumObj = DatabaseTypeEnums))
    @APIDOC_DECORATOR.ApiParams(value = 'name', require = True, type = 'string', desc = '数据库配置名称')
    @Authentication()
    def post(self, request, *args, **kwargs):
        try:
            body: dict = request.data.copy()
            userId, userName = RequestAuthTokenUtil(request = request).get_user_id_and_username()
            dbType = int(body.get('dbType'))
            queryset_name = self.Model.objects.filter(name = body.get('name'), deleted = False)
            if queryset_name.count() != 0:
                return CommonResponse(codeEnums = CommonResultEnums.DB_NAME_IS_EXIST)

            if dbType not in get_enum_key_list(enumObj = DatabaseTypeEnums):
                return CommonResponse(codeEnums = CommonResultEnums.DB_TYPE_NOT_SUPPORT)
            # 3. 保存
            with transaction.atomic():
                config_data = self.Model.objects.create(
                    name = body.get('name'),
                    dbType = dbType,
                    database = body.get('database'),
                    userName = body.get('userName'),
                    password = body.get('password'),
                    host = body.get('host'),
                    port = body.get('port'),
                    remark = body.get('remark'),
                    creatorId = userId,
                    creatorName = userName,
                )
            # 4. 序列化
            serializer = self.serializer_class(config_data, exclude = self.exclude_fields)

            return SuccessResponse(result = serializer.data)

        except Exception as e:
            logger.error(e)
            return SystemExceptionResponse()


class DatabaseConfigListAPIView(DatabaseConfigBaseAPIView):

    @APIDOC_DECORATOR.checkParams
    @APIDOC_DECORATOR.start
    @APIDOC_DECORATOR.ApiTag(value = 'config', desc = '配置管理')
    @APIDOC_DECORATOR.ApiOperation(method = 'POST', path = '/config/database/list', summary = '数据库配置列表')
    @APIDOC_DECORATOR.ApiParams(value = 'pageSize', type = 'string', require = True, desc = '每页数量')
    @APIDOC_DECORATOR.ApiParams(value = 'pageIndex', type = 'string', require = True, desc = '页码')
    @Authentication(flag = False)
    def post(self, request, *args, **kwargs):
        try:
            pageIndex, pageSize = request.data.get('pageIndex'), request.data.get('pageSize')
            if len(self.search_fields) != 0:
                queryset = self.Model.objects.filter(**self.search_queryset(request), deleted = False)
            else:
                queryset = self.Model.objects.filter(deleted = False)

            serializer = self.get_serializer(queryset, many = True)
            pageData = Paginator(serializer.data, pageSize)
            data = {
                'pageCount': pageData.count,
                'pageIndex': pageIndex,
                'pageSize': pageSize,
                'list': pageData.page(pageIndex).object_list
            }

            return SuccessResponse(result = data)
        except Exception as e:
            logger.error(e)
            return SystemExceptionResponse()


class DatabaseConfigEditAPIView(DatabaseConfigBaseAPIView):

    @APIDOC_DECORATOR.checkParams
    @APIDOC_DECORATOR.start
    @APIDOC_DECORATOR.ApiTag(value = 'config', desc = '配置管理')
    @APIDOC_DECORATOR.ApiOperation(method = 'POST', path = '/config/database/edit', summary = '数据库配置列表')
    @APIDOC_DECORATOR.ApiParams(value = 'remark', type = 'string', desc = '备注')
    @APIDOC_DECORATOR.ApiParams(value = 'port', type = 'int', desc = '端口')
    @APIDOC_DECORATOR.ApiParams(value = 'host', type = 'string', desc = '数据库地址')
    @APIDOC_DECORATOR.ApiParams(value = 'password', type = 'string', desc = '密码')
    @APIDOC_DECORATOR.ApiParams(value = 'userName', type = 'string', desc = '用户名')
    @APIDOC_DECORATOR.ApiParams(value = 'dbType', type = 'int', desc = '数据库类型',
                                remark = get_enum_str_list(enumObj = DatabaseTypeEnums))
    @APIDOC_DECORATOR.ApiParams(value = 'name', type = 'string', desc = '数据库配置名称')
    @APIDOC_DECORATOR.ApiParams(value = 'id', require = True, type = 'int', desc = '数据库配置id')
    @Authentication()
    def post(self, request, *args, **kwargs):
        try:
            body: dict = request.data.copy()
            userId, userName = RequestAuthTokenUtil(request = request).get_user_id_and_username()
            dbType = int(body.get('dbType'))

            queryset = self.Model.objects.filter(id = body.get('id'), deleted = False)
            if queryset.count() == 0:
                return CommonResponse(codeEnums = CommonResultEnums.DB_ID_IS_NOT_EXIST)

            queryset_name = self.Model.objects.filter(name = body.get('name'), deleted = False)
            if queryset_name.count() != 0 and queryset.first().name != body.get('name'):
                return CommonResponse(codeEnums = CommonResultEnums.DB_NAME_IS_EXIST)

            if dbType not in get_enum_key_list(enumObj = DatabaseTypeEnums):
                return CommonResponse(codeEnums = CommonResultEnums.DB_TYPE_NOT_SUPPORT)

            with transaction.atomic():
                queryset.update(
                    name = body.get('name'),
                    dbType = dbType,
                    database = body.get('database'),
                    userName = body.get('userName'),
                    password = body.get('password'),
                    host = body.get('host'),
                    port = body.get('port'),
                    remark = body.get('remark'),
                    updaterId = userId,
                    updaterName = userName,
                    updateTime = get_time(),
                )
            return SuccessResponse()
        except Exception as e:
            logger.error(e)
            return SystemExceptionResponse()


class DatabaseConfigDeleteAPIView(DatabaseConfigBaseAPIView):

    @APIDOC_DECORATOR.checkParams
    @APIDOC_DECORATOR.start
    @APIDOC_DECORATOR.ApiTag(value = 'config', desc = '配置管理')
    @APIDOC_DECORATOR.ApiOperation(method = 'POST', path = '/config/database/delete', summary = '数据库配置列表')
    @APIDOC_DECORATOR.ApiParams(value = 'id', require = True, type = 'int', desc = '数据库配置id')
    @Authentication()
    def post(self, request, *args, **kwargs):
        try:
            body: dict = request.data.copy()
            userId, userName = RequestAuthTokenUtil(request = request).get_user_id_and_username()

            # 1. 判断id是否存在
            queryset_id = self.Model.objects.filter(id = body.get('id'), deleted = False)
            if queryset_id.count() == 0:
                return CommonResponse(codeEnums = CommonResultEnums.DB_ID_IS_NOT_EXIST)
            # 2. 更新
            with transaction.atomic():
                queryset_id.update(
                    deleted = True,
                    deleteTime = get_time(),
                    updaterId = userId,
                    updaterName = userName,
                    updateTime = get_time(),
                )
            return SuccessResponse()
        except Exception as e:
            logger.error(e)
            return SystemExceptionResponse()


class DatabaseConfigDatabaseAPIView(DatabaseConfigBaseAPIView):

    @APIDOC_DECORATOR.checkParams
    @APIDOC_DECORATOR.start
    @APIDOC_DECORATOR.ApiTag(value = 'config', desc = '配置管理')
    @APIDOC_DECORATOR.ApiOperation(method = 'POST', path = '/config/database/database', summary = '查询数据库库列表')
    @APIDOC_DECORATOR.ApiParams(value = 'serverId', require = True, type = 'int', desc = '数据库配置id')
    @Authentication(flag = False)
    def post(self, request, *args, **kwargs):
        try:
            body: dict = request.data.copy()
            commonMapper = self.database_connect(serverId = body.get('serverId'))
            data = commonMapper.databaseList()
            return SuccessResponse(result = data)
        except DatabaseConfigTypeException:
            return CommonResponse(codeEnums = CommonResultEnums.DB_TYPE_NOT_SUPPORT)
        except DatabaseConfigConnectException:
            return CommonResponse(codeEnums = CommonResultEnums.DB_CONNECT_EXCEPTION)
        except Exception as e:
            logger.error(e)
            return SystemExceptionResponse()


class DatabaseConfigTableAPIView(DatabaseConfigBaseAPIView):

    @APIDOC_DECORATOR.checkParams
    @APIDOC_DECORATOR.start
    @APIDOC_DECORATOR.ApiTag(value = 'config', desc = '配置管理')
    @APIDOC_DECORATOR.ApiOperation(method = 'POST', path = '/config/database/table', summary = '查询数据库所有的表')
    @APIDOC_DECORATOR.ApiParams(value = 'dbName', require = True, type = 'string', desc = '数据库名称')
    @APIDOC_DECORATOR.ApiParams(value = 'serverId', require = True, type = 'int', desc = '数据库配置id')
    @Authentication(flag = False)
    def post(self, request, *args, **kwargs):
        try:
            body: dict = request.data.copy()
            commonMapper = self.database_connect(serverId = body.get('serverId'))
            data = commonMapper.tableList(dbId = body.get('dbName'))
            return SuccessResponse(result = data)
        except DatabaseConfigTypeException:
            return CommonResponse(codeEnums = CommonResultEnums.DB_TYPE_NOT_SUPPORT)
        except DatabaseConfigConnectException:
            return CommonResponse(codeEnums = CommonResultEnums.DB_CONNECT_EXCEPTION)
        except Exception as e:
            logger.error(e)
            return SystemExceptionResponse()


class DatabaseConfigColumnAPIView(DatabaseConfigBaseAPIView):

    @APIDOC_DECORATOR.checkParams
    @APIDOC_DECORATOR.start
    @APIDOC_DECORATOR.ApiTag(value = 'config', desc = '配置管理')
    @APIDOC_DECORATOR.ApiOperation(method = 'POST', path = '/config/database/column', summary = '查询表字段')
    @APIDOC_DECORATOR.ApiParams(value = 'tableName', require = True, type = 'string', desc = '数据库表名称')
    @APIDOC_DECORATOR.ApiParams(value = 'dbName', require = True, type = 'string', desc = '数据库名称')
    @APIDOC_DECORATOR.ApiParams(value = 'serverId', require = True, type = 'int', desc = '数据库配置id')
    @Authentication(flag = False)
    def post(self, request, *args, **kwargs):
        try:
            body: dict = request.data.copy()
            commonMapper = self.database_connect(serverId = body.get('serverId'))
            data = commonMapper.columnList(dbName = body.get('dbName'), tableName = body.get('tableName'))
            return SuccessResponse(result = data)
        except DatabaseConfigTypeException:
            return CommonResponse(codeEnums = CommonResultEnums.DB_TYPE_NOT_SUPPORT)
        except DatabaseConfigConnectException:
            return CommonResponse(codeEnums = CommonResultEnums.DB_CONNECT_EXCEPTION)
        except Exception as e:
            logger.error(e)
            return SystemExceptionResponse()


class DatabaseConfigIndexAPIView(DatabaseConfigBaseAPIView):

    @APIDOC_DECORATOR.checkParams
    @APIDOC_DECORATOR.start
    @APIDOC_DECORATOR.ApiTag(value = 'config', desc = '配置管理')
    @APIDOC_DECORATOR.ApiOperation(method = 'POST', path = '/config/database/index', summary = '查询表索引')
    @APIDOC_DECORATOR.ApiParams(value = 'tableName', require = True, type = 'string', desc = '数据库表名称')
    @APIDOC_DECORATOR.ApiParams(value = 'dbName', require = True, type = 'string', desc = '数据库名称')
    @APIDOC_DECORATOR.ApiParams(value = 'serverId', require = True, type = 'int', desc = '数据库配置id')
    @Authentication(flag = False)
    def post(self, request, *args, **kwargs):
        try:
            body: dict = request.data.copy()
            commonMapper = self.database_connect(serverId = body.get('serverId'))
            data = commonMapper.indexList(dbName = body.get('dbName'), tableName = body.get('tableName'))
            return SuccessResponse(result = data)
        except DatabaseConfigTypeException:
            return CommonResponse(codeEnums = CommonResultEnums.DB_TYPE_NOT_SUPPORT)
        except DatabaseConfigConnectException:
            return CommonResponse(codeEnums = CommonResultEnums.DB_CONNECT_EXCEPTION)
        except Exception as e:
            logger.error(e)
            return SystemExceptionResponse()


urlpatterns = [
    url('database/add', DatabaseConfigAddAPIView.as_view()),
    url('database/list', DatabaseConfigListAPIView.as_view()),
    url('database/edit', DatabaseConfigEditAPIView.as_view()),
    url('database/delete', DatabaseConfigDeleteAPIView.as_view()),
    url('database/database', DatabaseConfigDatabaseAPIView.as_view()),
    url('database/table', DatabaseConfigTableAPIView.as_view()),
    url('database/column', DatabaseConfigColumnAPIView.as_view()),
    url('database/index', DatabaseConfigIndexAPIView.as_view()),
]
